package com.siteseat.common.misc;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;

/**
 *
 */
public class IOHelper {

  public static final Charset CHARSET = Charset.forName( "utf-8" );
  
  /**
   * @param data
   * @param offset
   * @return
   */
  public static short readShort( byte[] data, int offset ) {
    return (short)( ( (data[offset + 1] & 0xFF) << 0 ) | ( (data[offset + 0] & 0xFF) << 8 ) );
  }

  public static short readShort( InputStream ins ) throws IOException {
    int b8 = ins.read();
    if( b8 == -1 ) {
      throw new EOFException();
    }
    int b0 = ins.read();
    if( b0 == -1 ) {
      throw new EOFException();
    }
    return (short)( ( b0 << 0 ) | ( b8 << 8 ) );
  }

  public static void writeShort( byte[] data, int offset, short v ) {
    data[offset + 1] = (byte)( v >>> 0 );
    data[offset + 0] = (byte)( v >>> 8 );
  }

  public static void writeShort( OutputStream ous, short v ) throws IOException {
    ous.write( ( v >>> 8 ) );
    ous.write( ( v >>> 0 ) );
  }


  public static int readInt( InputStream ins ) throws IOException {
    int b24 = ins.read();
    if( b24 == -1 ) {
      throw new EOFException();
    }
    int b16 = ins.read();
    if( b16 == -1 ) {
      throw new EOFException();
    }
    int b8 = ins.read();
    if( b8 == -1 ) {
      throw new EOFException();
    }
    int b0 = ins.read();
    if( b0 == -1 ) {
      throw new EOFException();
    }
    return ( b0 << 0 ) | ( b8 << 8 ) | ( b16 << 16 ) | ( b24 << 24 );
  }
  
  public static void writeInt( OutputStream ous, int v ) throws IOException {
    ous.write( v >>> 24 );
    ous.write( v >>> 16 );
    ous.write( v >>>  8 );
    ous.write( v >>>  0 );
  }
  
  /**
   * @param data
   * @param offset
   * @return
   */
  public static int readInt( byte[] data, int offset ) {
    return ((data[offset + 3] & 0xFF) << 0)
         | ((data[offset + 2] & 0xFF) << 8)
         | ((data[offset + 1] & 0xFF) << 16)
         | ((data[offset + 0] & 0xFF) << 24);
  }

  public static void writeInt( byte[] data, int offset, int v ) {
    data[offset + 3] = (byte)( v >>> 0 );
    data[offset + 2] = (byte)( v >>> 8 );
    data[offset + 1] = (byte)( v >>> 16 );
    data[offset + 0] = (byte)( v >>> 24 );
  }



  /**
   * @param data
   * @param offset
   * @return
   */
  public static long readLong( byte[] data, int offset ) {
    long low  =   ( (data[offset + 7] & 0xFF) << 0 ) 
                | ( (data[offset + 6] & 0xFF) << 8 ) 
                | ( (data[offset + 5] & 0xFF) << 16 ) 
                | ( (long)(data[offset + 4] & 0xFF) << 24 );
    
    long high =   ( (data[offset + 3] & 0xFF) << 0 ) 
                | ( (data[offset + 2] & 0xFF) << 8 ) 
                | ( (data[offset + 1] & 0xFF) << 16 ) 
                | ( (long)(data[offset + 0] & 0xFF) << 24 );
    high <<= 32;
    
    return high | low;
  }
  

  public static void writeLong( byte[] data, int offset, long v ) {
    data[offset + 7] = (byte)( v >>> 0 );
    data[offset + 6] = (byte)( v >>> 8 );
    data[offset + 5] = (byte)( v >>> 16 );
    data[offset + 4] = (byte)( v >>> 24 );
    data[offset + 3] = (byte)( v >>> 32 );
    data[offset + 2] = (byte)( v >>> 40 );
    data[offset + 1] = (byte)( v >>> 48 );
    data[offset + 0] = (byte)( v >>> 56 );
  }

  public static long readLong( InputStream ins ) throws IOException {
    int b56 = ins.read();
    if( b56 == -1 ) {
      throw new EOFException();
    }
    int b48 = ins.read();
    if( b48 == -1 ) {
      throw new EOFException();
    }
    int b40 = ins.read();
    if( b40 == -1 ) {
      throw new EOFException();
    }
    int b32 = ins.read();
    if( b32 == -1 ) {
      throw new EOFException();
    }
    int b24 = ins.read();
    if( b24 == -1 ) {
      throw new EOFException();
    }
    int b16 = ins.read();
    if( b16 == -1 ) {
      throw new EOFException();
    }
    int b8 = ins.read();
    if( b8 == -1 ) {
      throw new EOFException();
    }
    int b0 = ins.read();
    if( b0 == -1 ) {
      throw new EOFException();
    }
    
    long low = ( b0 << 0 ) 
            | ( b8 << 8 ) 
            | ( b16 << 16 ) 
            | ( (long)b24 << 24 );
    long high =  ( b32 << 32 ) 
               | ( b40 << 40 ) 
               | ( b48 << 48 ) 
               | (long)( b56 << 56 );
    high <<= 32;    
    return high | low;
  }

  public static void writeLong( OutputStream ous, long v ) throws IOException {
    ous.write( (int)( v >>> 56 ) );
    ous.write( (int)( v >>> 48 ) );
    ous.write( (int)( v >>> 40 ) );
    ous.write( (int)( v >>> 32 ) );
    ous.write( (int)( v >>> 24 ) );
    ous.write( (int)( v >>> 16 ) );
    ous.write( (int)( v >>> 8 ) );
    ous.write( (int)( v >>> 0 ) );
  }

  /**
   * @param data
   * @param start
   * @return
   */
  public static boolean readBoolean( byte[] data, int offset ) {
    return 1 == data[offset];
  }

  /**
   * @param data
   * @param start
   * @return
   */
  public static void writeBoolean( byte[] data, int offset, boolean valid ) {
    data[offset] = (byte)( valid ? 1 : 0 );
  }

  /**
   * @param result
   * @throws IOException
   */
  public static void readBytes( InputStream ins, byte[] result ) throws IOException {
    int offset = 0;
    while( offset < result.length ) {
      int got = ins.read( result, offset, result.length - offset );
      if( got < 0 ) {
        throw new EOFException( "Only got " + offset + " bytes" );
      }
      offset += got;
    }
  }

}
